package com.aurora.base.dao;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.aurora.base.dto.Order;
import com.aurora.base.dto.QueryResult;
import com.aurora.base.util.EntityUtils;
import com.aurora.base.util.PageContent;
import com.aurora.exption.DaoException;




public abstract class BaseDao <T extends Serializable>{
	// 如果在jboss中使用的话，则下面的这个换成这个
		@PersistenceContext
		protected EntityManager em;//
		// JPAUtils.getEntityManager();
		// protected EntityManager em = JPAUtils.getEntityManager();

		@Resource
		protected JdbcTemplate jdbcTemplate;

		@Resource
		protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;

		// @Resource
		// protected RedisTemplate<String, String> redisTemplate;

		/**
		 * 日志记录
		 */
		protected Logger LOG = LoggerFactory.getLogger(this.getClass());
		/**
		 * 泛型class
		 */
		@SuppressWarnings("unchecked")
		protected Class<T> entityClass = (Class<T>) EntityUtils.getEntityClass(this
				.getClass());
		/**
		 * 实体名称
		 */
		protected String entityName = this.getEntityName();
		/**
		 * 实体id名称
		 */
		protected String entityIdName = this.getEntityIdName();

		/**
		 * 更新实体
		 * 
		 * @param entity
		 *            实体
		 * @throws DaoException
		 *             当jpa运行时发生错误时抛出
		 */
		public T merge(T entity) {
			T result = null;
			try {
				result = this.getEntityManager().merge(entity);
				if (this.LOG.isDebugEnabled())
					this.LOG.debug("实体" + entity.getClass() + "保存成功");
			} catch (Exception e) {
				if (this.LOG.isDebugEnabled())
					this.LOG.debug("实体" + entity.getClass() + "保存成功");
				throw new DaoException(e);
			}
			return result;
		}

		/**
		 * 持久化实体
		 * 
		 * @param entity
		 *            实体
		 * @throws DaoException
		 *             当jpa运行时发生错误时抛出
		 */
		public void persist(T entity) {
			try {
				this.getEntityManager().persist(entity);
				if (this.LOG.isDebugEnabled())
					this.LOG.debug("实体" + entity.getClass() + "保存成功");
			} catch (Exception e) {
				throw new DaoException(e);
			}
		}

		/**
		 * 删除实体
		 * 
		 * @param entityIds
		 *            实体id数组
		 * @throws DaoException
		 *             当jpa运行时发生错误时抛出
		 */
		public void remove(Serializable... entityIds) {
			EntityManager em = this.getEntityManager();
			try {
				for (Serializable entityId : entityIds) {
					em.remove(em.getReference(this.entityClass, entityId));
				}
			} catch (Exception e) {
				throw new DaoException(e);
			}
		}

		/**
		 * 通过实体id获得实体
		 * 
		 * @param entityId
		 *            实体id
		 * @return 存在返回实体，不存在返回null
		 */
		public T find(Serializable entityId) {
			return this.getEntityManager().find(this.entityClass, entityId);
		}

		/**
		 * 通过实体id获得实体
		 * 
		 * @param entityId
		 *            实体id
		 * @param lockModeType
		 *            the lock mode to obtain
		 * @return 存在返回实体，不存在返回null
		 */
		public T find(Serializable entityId, LockModeType lockModeType) {
			return this.getEntityManager().find(this.entityClass, entityId,
					lockModeType);
		}

		/**
		 * 通过条件获得实体
		 * 
		 * @param whereSql
		 *            条件， 如："o.username=? and o.password=?" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 * @return 存在返回实体，不存在返回null
		 */
		public T find(String whereSql, Object... params) {
			StringBuilder jpqlBuilder = new StringBuilder();
			jpqlBuilder.append("select o from ").append(this.entityName)
					.append(" o ");
			buildWhereSql(whereSql, jpqlBuilder);
			TypedQuery<T> query = this.getQueryWithDefaultType(jpqlBuilder
					.toString());
			setParameters(query, params);
			T t = null;
			try {
				List<T> results = query.getResultList();
				if (null != results && !results.isEmpty()) {
					if (results.size() == 1) {
						t = results.get(0);
					} else {
						throw new NonUniqueResultException();
					}
				}
			} catch (NonUniqueResultException e) {
				if (this.LOG.isErrorEnabled()) {
					StringBuilder sb = new StringBuilder();
					for (Object param : params) {
						sb.append(param).append(" ");
					}
					this.LOG.error(jpqlBuilder.toString() + ":" + sb.toString()
							+ "：查询的结果有重复的记录", e);
				}
			} catch (IllegalStateException e) {
				if (this.LOG.isErrorEnabled()) {
					StringBuilder sb = new StringBuilder();
					for (Object param : params) {
						sb.append(param).append(" ");
					}
					this.LOG.error(jpqlBuilder.toString() + ":" + sb.toString()
							+ "：输入的SQL语句有误", e);
				}
			}
			return t;
		}

		public QueryResult<T> query(int firstResult, int maxResults,
				String whereSql, Object... params) {
			return this.query(null, firstResult, maxResults, whereSql, params);
		}

		public QueryResult<T> query(int firstResult, int maxResults) {
			return this.query(null, firstResult, maxResults, null, new Object[0]);
		}

		/**
		 * 通过条件，排序获得实体个数。
		 * 
		 * @param whereSql
		 *            条件， 如："o.username=? and o.password=?" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            <p>
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 *            更新为可变参数，传入数组也是可以的
		 *            </p>
		 * @return 存在记录返回大于0的整数，不存在返回0。
		 */
		public long getCount(String whereSql, Object... params) {
			StringBuilder jpqlBuilder = new StringBuilder("select count(o) from ");
			jpqlBuilder.append(this.entityName).append(" o ");
			buildWhereSql(whereSql, jpqlBuilder);
			TypedQuery<Long> query = this.getQuery(jpqlBuilder.toString(),
					Long.class);
			setParameters(query, params);
			Long singleResult = query.getSingleResult();
			return singleResult == null ? 0L : (Long) singleResult;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.blackants.core.dao.BaseDao#update(java.lang.String,
		 * java.lang.Object[])
		 */
		/**
		 * 直接使用jpql语句进行修改操作
		 * 
		 * @param jpql
		 * @param params
		 * @return
		 */
		public int update(String jpql, Object... params) {
			Query query = this.getQuery(jpql);
			setParameters(query, params);
			return query.executeUpdate();
		}

		public Object queryForProperty(String property, Serializable entityId) {
			String jpql = "select o." + property + " from " + this.entityName
					+ " o where o." + this.entityIdName + "=?1";
			try {
				return this.getQuery(jpql).setParameter(1, entityId)
						.getSingleResult();
			} catch (NoResultException e) {
				return null;
			}
		}

		public void updateProperty(String property, Object value,
				Serializable entityId) {
			this.updateProperties(new String[]{property}, new Object[]{value},
					entityId);
		}

		public void updateProperties(String[] properties, Object[] values,
				Serializable entityId) {
			String jpql = "update " + this.entityName + " o set "
					+ buildProperties(properties) + " where o." + this.entityIdName
					+ "=?";
			Query query = this.getQuery(jpql);
			setParameters(query, values);
			query.setParameter(values.length + 1, entityId);
			int count = query.executeUpdate();
			if (count != 1)
				throw new DaoException("更新失败");
		}

		public boolean isEntityExist(Serializable entityId) {
			return this.isEntityExist("o." + this.entityIdName + "=?1", entityId);
		}

		public boolean isEntityExist(String whereSql, Object... params) {
			return this.getCount(whereSql, params) > 0L;
		}

		public boolean contain(String jpql, Serializable entityId, Object obj) {
			Query query = this.getQuery("select count(o) from " + this.entityName
					+ " o where o." + this.entityIdName + "=?1 and ?2 member of "
					+ jpql, Long.class);
			setParameters(query, new Object[]{entityId, obj});
			return ((Long) query.getSingleResult() > 0);
		}

		/**
		 * 通过条件，排序获得实体列表。
		 * 
		 * @param whereSql
		 *            条件， 如："o.username=?1 and o.password=?2" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 * @param order
		 *            排序语句，如：order.put("username",Order.ASC)升序
		 *            或者order.put("username",Order.DESC)降序; 例子：Order order = new
		 *            Order(); order.put("username",Order.DESC);
		 * @return 返回List对象，里面包含T
		 */
		public List<T> list(Order order, String whereSql, Object... params) {
			return this.list(order, -1, -1, whereSql, params);
		}

		/**
		 * 有分页,通过条件，排序获得实体列表。
		 * 
		 * @param firstResult
		 *            第一个记录数 大于-1的时候才会分页
		 * @param maxResults
		 *            最大记录数 大于-1的时候才会分页
		 * @param whereSql
		 *            条件， 如："o.username=?1 and o.password=?2" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 * @param order
		 *            排序语句，如：order.put("username",Order.ASC)升序
		 *            或者order.put("username",Order.DESC)降序; 例子：Order order = new
		 *            Order(); order.put("username",Order.DESC);
		 * @return 返回List对象，里面包含T
		 */
		public List<T> list(Order order, int firstResult, int maxResults,
				String whereSql, Object... params) {
			StringBuilder jpql = new StringBuilder("select ");
			jpql.append(" o from ");
			jpql.append(this.entityName).append(" o ");
			buildWhereSql(whereSql, jpql);
			buildOrderBy(order, jpql);
			if (this.LOG.isInfoEnabled())
				this.LOG.info(jpql.toString());
			TypedQuery<T> query = this.getQueryWithDefaultType(jpql.toString());
			// 设置参数
			setParameters(query, params);
			if (firstResult != -1 && maxResults != -1)
				query.setFirstResult(firstResult).setMaxResults(maxResults);
			return query.getResultList();
		}

		public List<T> listLock(Order order, int firstResult, int maxResults,
				String whereSql, Object... params) {
			StringBuilder jpql = new StringBuilder("select ");
			jpql.append(" o from ");
			jpql.append(this.entityName).append(" o ");
			buildWhereSql(whereSql, jpql);
			buildOrderBy(order, jpql);
			if (this.LOG.isInfoEnabled())
				this.LOG.info(jpql.toString());
			TypedQuery<T> query = this.getQueryWithDefaultTypeLock(jpql.toString());
			// 设置参数
			setParameters(query, params);
			if (firstResult != -1 && maxResults != -1)
				query.setFirstResult(firstResult).setMaxResults(maxResults);
			return query.getResultList();
		}

		/**
		 * 通过条件获得实体列表。
		 * 
		 * @param whereSql
		 *            条件， 如："o.username=? and o.password=?" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            <p>
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 *            更新为可变参数，传入对象数组也是可以的
		 *            </p>
		 * @return 返回List对象，里面包含T
		 */
		public List<T> list(String whereSql, Object... params) {
			return this.list(null, -1, -1, whereSql, params);
		}

		/**
		 * 有分页，通过条件，排序获得实体列表。
		 * 
		 * @param firstResult
		 *            第一个记录数 大于-1的时候才会分页
		 * @param maxResults
		 *            最大记录数 大于-1的时候才会分页
		 * @param whereSql
		 *            条件， 如："o.username=? and o.password=?" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 * @return 返回List对象，里面包含T
		 */
		public List<T> list(int firstResult, int maxResults, String whereSql,
				Object... params) {
			return this.list(null, firstResult, maxResults, whereSql, params);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.blackants.core.dao.BaseDao#listJoin(com.blackants.core.dto.Order,
		 * java.lang.String, int, int, java.lang.String, java.lang.Object[])
		 */

		/**
		 * 有分页,通过条件，排序获得实体列表。
		 * 
		 * @param firstResult
		 *            第一个记录数 大于-1的时候才会分页
		 * @param maxResults
		 *            最大记录数 大于-1的时候才会分页
		 * @param join
		 *            联合查询
		 * @param whereSql
		 *            条件， 如："o.username=?1 and o.password=?2" 为空或者为""则不会处理。Hibernate
		 *            4推荐最新的编写方式,必须按着1,2,3的方式定义
		 *            "o.username=? and o.password=?"的方式还是可行的
		 * @param params
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 * @param order
		 *            排序语句，如：order.put("username",Order.ASC)升序
		 *            或者order.put("username",Order.DESC)降序; 例子：Order order = new
		 *            Order(); order.put("username",Order.DESC);
		 * @return 返回List对象，里面包含T
		 */
		public List<T> listJoin(Order order, String join, int firstResult,
				int maxResults, String whereSql, Object... params) {
			boolean flag = (null != join && !"".equals(join.trim()));
			StringBuilder jpql = new StringBuilder("select ");
			if (flag)
				jpql.append(" distinct ");
			jpql.append(" o from ");
			jpql.append(this.entityName).append(" o ");
			if (flag)
				jpql.append(" ").append(join).append(" ");
			buildWhereSql(whereSql, jpql);
			buildOrderBy(order, jpql);
			if (this.LOG.isInfoEnabled())
				this.LOG.info(jpql.toString());
			TypedQuery<T> query = this.getQueryWithDefaultType(jpql.toString());
			// 设置参数
			setParameters(query, params);
			if (firstResult != -1 && maxResults != -1)
				query.setFirstResult(firstResult).setMaxResults(maxResults);
			return query.getResultList();
		}

		/**
		 * 有分页，条件，参数，排序
		 * 
		 * @param firstResult
		 *            第一个记录数 大于-1的时候才会分页
		 * @param maxResults
		 *            最大记录数 大于-1的时候才会分页
		 * @param whereSql
		 *            条件， 如："o.username=? and o.password=?" 为空或者为""则不会处理。
		 * @param params
		 *            参数，是一个数组{"xxxx","xxx"},个数必须与whereSql语句中的？的个数一致，为空或者0个元素则不设置值。
		 * @param order
		 *            排序语句，如：order.put("username",Order.ASC)升序
		 *            或者order.put("username",Order.DESC)降序; 例子：Order order = new
		 *            Order(); order.put("username",Order.DESC);
		 * @return 返回QueryResult对象，里面包含results（List<T>），count(Long)。分别为总记录，总记录数
		 * @see com.blackants.core.dto.QueryResult
		 */
		public QueryResult<T> query(Order order, int firstResult, int maxResults,
				String whereSql, Object... params) {
			StringBuilder countBuilder = new StringBuilder();
			countBuilder.append("select count(o) from ").append(this.entityName)
					.append(" o ");
			StringBuilder followBuilder = new StringBuilder();
			// 拼凑where语句
			buildWhereSql(whereSql, followBuilder);

			countBuilder.append(followBuilder);
			TypedQuery<Long> countQuery = this.getQuery(countBuilder.toString(),
					Long.class);
			setParameters(countQuery, params);
			long count = countQuery.getSingleResult();
			// 如果没有记录数为0则不必继续查了，直接返回。
			if (count < 1)
				return new QueryResult<T>(null, 0, false);

			StringBuilder resultBuilder = new StringBuilder();
			resultBuilder.append("select ");
			resultBuilder.append(" o from ").append(this.entityName).append(" o ");
			// 拼凑orderBy语句
			buildOrderBy(order, followBuilder);
			resultBuilder.append(followBuilder);
			TypedQuery<T> resultQuery = this.getQueryWithDefaultType(resultBuilder
					.toString());
			setParameters(resultQuery, params);
			if (firstResult > -1 && maxResults > -1)
				resultQuery.setFirstResult(firstResult).setMaxResults(maxResults);
			List<T> results = resultQuery.getResultList();
			return new QueryResult<T>(results, count, false);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.blackants.core.dao.BaseDao#queryJoin(com.blackants.core.dto.Order,
		 * java.lang.String, java.lang.String, int, int, java.lang.String,
		 * java.lang.Object[])
		 */

		public QueryResult<T> queryJoin(Order order, String countJoin, String join,
				int firstResult, int maxResults, String whereSql, Object... params) {
			StringBuilder countBuilder = new StringBuilder();
			countBuilder.append("select count(distinct o) from ")
					.append(this.entityName).append(" o ");
			if (null != countJoin && !"".equals(countJoin.trim()))
				countBuilder.append(" ").append(countJoin).append(" ");
			StringBuilder followBuilder = new StringBuilder();
			// 拼凑where语句
			buildWhereSql(whereSql, followBuilder);

			countBuilder.append(followBuilder);
			TypedQuery<Long> countQuery = this.getQuery(countBuilder.toString(),
					Long.class);
			setParameters(countQuery, params);
			long count = countQuery.getSingleResult();
			// 如果没有记录数为0则不必继续查了，直接返回。
			if (count < 1)
				return new QueryResult<T>(null, 0, false);

			StringBuilder resultBuilder = new StringBuilder();
			boolean flag = (null != join && !"".equals(join.trim()));
			resultBuilder.append("select ");
			if (flag)
				resultBuilder.append(" distinct ");
			resultBuilder.append(" o from ").append(this.entityName).append(" o ");
			if (flag)
				resultBuilder.append(" ").append(join).append(" ");
			// 拼凑orderBy语句
			buildOrderBy(order, followBuilder);
			resultBuilder.append(followBuilder);
			TypedQuery<T> resultQuery = this.getQueryWithDefaultType(resultBuilder
					.toString());
			setParameters(resultQuery, params);
			if (firstResult > -1 && maxResults > -1)
				resultQuery.setFirstResult(firstResult).setMaxResults(maxResults);
			List<T> results = resultQuery.getResultList();
			return new QueryResult<T>(results, count, false);
		}

		/**
		 * pageContent 分页查询
		 * 
		 * @param request
		 * @param order
		 * @param whereSql
		 * @param params
		 * @return
		 */
		public QueryResult<T> query(HttpServletRequest request, Order order,
				String whereSql, Object... params) {
			StringBuilder countBuilder = new StringBuilder();
			countBuilder.append("select count(o) from ").append(this.entityName)
					.append(" o ");
			StringBuilder followBuilder = new StringBuilder();
			// 拼凑where语句
			buildWhereSql(whereSql, followBuilder);

			countBuilder.append(followBuilder);
			TypedQuery<Long> countQuery = this.getQuery(countBuilder.toString(),
					Long.class);
			setParameters(countQuery, params);
			long count = countQuery.getSingleResult();
			// 如果没有记录数为0则不必继续查了，直接返回。
			if (count < 1)
				return new QueryResult<T>(null, 0, true);

			PageContent pageCnt = PageContent.getPageContent(count, request);
			StringBuilder resultBuilder = new StringBuilder();
			resultBuilder.append("select ");
			resultBuilder.append(" o from ").append(this.entityName).append(" o ");
			// 拼凑orderBy语句
			buildOrderBy(order, followBuilder);
			resultBuilder.append(followBuilder);
			TypedQuery<T> resultQuery = this.getQueryWithDefaultType(resultBuilder
					.toString());
			setParameters(resultQuery, params);
			int firstResult = pageCnt.getBeginRow();
			int maxResults = pageCnt.getPageSize();
			if (firstResult > -1 && maxResults > -1)
				resultQuery.setFirstResult(firstResult).setMaxResults(maxResults);
			List<T> results = resultQuery.getResultList();
			boolean isLast = false;
			int totalPage = pageCnt.getPageCount();
			if (pageCnt.getCurrentPage() >= totalPage) {
				isLast = true;
			}

			return new QueryResult<T>(results, count, isLast);
		}
		/**
		 * pageContent 分页查询特殊hql无法执行count的语句
		 * 
		 * @param request
		 * @param order
		 * @param whereSql
		 * @param params
		 * @return
		 */

		public QueryResult<T> query(HttpServletRequest request, int count,
				Order order, String whereSql, Object... params) {

			StringBuilder countBuilder = new StringBuilder();
			countBuilder.append("select count(o) from ").append(this.entityName)
					.append(" o ");
			StringBuilder followBuilder = new StringBuilder();
			// 拼凑where语句
			buildWhereSql(whereSql, followBuilder);

			// 如果没有记录数为0则不必继续查了，直接返回。
			if (count < 1)
				return new QueryResult<T>(new ArrayList<T>(), 0, true);

			PageContent pageCnt = PageContent.getPageContent(count, request);
			StringBuilder resultBuilder = new StringBuilder();
			resultBuilder.append("select ");
			resultBuilder.append(" o from ").append(this.entityName).append(" o ");
			// 拼凑orderBy语句
			buildOrderBy(order, followBuilder);
			resultBuilder.append(followBuilder);
			TypedQuery<T> resultQuery = this.getQueryWithDefaultType(resultBuilder
					.toString());
			setParameters(resultQuery, params);
			int firstResult = pageCnt.getBeginRow();
			int maxResults = pageCnt.getPageSize();
			if (firstResult > -1 && maxResults > -1)
				resultQuery.setFirstResult(firstResult).setMaxResults(maxResults);
			List<T> results = resultQuery.getResultList();
			boolean isLast = false;
			int totalPage = pageCnt.getPageCount();
			if (pageCnt.getCurrentPage() >= totalPage) {
				isLast = true;
			}

			return new QueryResult<T>(results, count, isLast);
		}

		public QueryResult<T> query(Order order, int firstResult, int maxResults) {
			return this.query(order, firstResult, maxResults, null);
		}

		public QueryResult<T> query(Order order, String whereSql, Object... params) {
			return this.query(order, -1, -1, whereSql, params);
		}

		public QueryResult<T> query(String whereSql, Object... params) {
			return this.query(null, -1, -1, whereSql, params);
		}

		public void detach(T entity) {
			this.getEntityManager().detach(entity);
		}

		public void detach(T[] entities) {
			EntityManager em = this.getEntityManager();
			for (T entity : entities) {
				em.detach(entity);
			}
		}

		public void flush() {
			this.getEntityManager().flush();
		}

		public void refresh(T entity) {
			try {
				this.getEntityManager().refresh(entity);
			} catch (Exception e) {
				throw new DaoException(e);
			}
		}

		public void refresh(T entity, LockModeType lockModeType) {
			try {
				this.getEntityManager().refresh(entity, lockModeType);
			} catch (Exception e) {
				throw new DaoException(e);
			}
		}

		public void clear() {
			this.getEntityManager().clear();
		}

		public Long getSum(String field, String whereSql, Object[] params) {
			StringBuilder sb = new StringBuilder("");
			buildWhereSql(whereSql, sb);
			String jpql = "select sum(" + field + ") from " + this.entityName
					+ " o " + sb.toString();
			Query query = this.getQuery(jpql);
			setParameters(query, params);
			Object singleResult = query.getSingleResult();
			return singleResult == null ? 0 : (Long) singleResult;
		}

		public <E> List<E> list(String jpql, Object[] params, int firstResult,
				int maxResults, Class<E> resultClass) {
			TypedQuery<E> query = this.getQuery(jpql, resultClass);
			setParameters(query, params);
			if (firstResult > -1 && maxResults > -1)
				query.setFirstResult(firstResult).setMaxResults(maxResults);
			return query.getResultList();
		}

		public <E> List<E> list(String jpql, Object[] params, Class<E> resultClass) {
			return this.list(jpql, params, -1, -1, resultClass);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.tentcoo.core.dao.BaseDao#updateSQL(java.lang.String,
		 * java.lang.Object[])
		 */

		public int updateSQL(String sql, Object... params) {
			Query query = this.getEntityManager().createNativeQuery(sql);
			setParameters(query, params);
			return query.executeUpdate();
		}

		public List selectSQL(String sql, Object... params) {
			Query query = this.getEntityManager().createNativeQuery(sql);
			setParameters(query, params);
			return query.getResultList();
		}

		public List selectSQL(LockModeType lockModeType, String sql,
				Object... params) {

			Query query = this.getEntityManager().createNativeQuery(sql);

			query.setLockMode(lockModeType);
			setParameters(query, params);
			return query.getResultList();
		}

		public List selectSQLQuery(HttpServletRequest request, long count,
				String sql, Object... params) {

			PageContent pageCnt = PageContent.getPageContent(count, request);
			int firstResult = pageCnt.getBeginRow();
			int maxResults = pageCnt.getPageSize();
			Query query = this.getEntityManager().createNativeQuery(sql);
			setParameters(query, params);
			query.setFirstResult(firstResult);
			query.setMaxResults(maxResults);
			return query.getResultList();
		}
		public List selectSQLByPage(HttpServletRequest request, long count,
				String sql, Object... params) {
			if (count < 1) {
				return null;
			}
			PageContent pageCnt = PageContent.getPageContent(count, request);
			int firstResult = pageCnt.getBeginRow();
			int maxResults = pageCnt.getPageSize();
			return this.selectSQLByPage(request, firstResult, maxResults, sql,
					params);
		}

		public List selectSQLByPage(HttpServletRequest request, int firstResult,
				int maxResults, String sql, Object... params) {
			Query query = this.getEntityManager().createNativeQuery(sql);
			setParameters(query, params);
			query.setFirstResult(firstResult);
			query.setMaxResults(maxResults);
			return query.getResultList();
		}

		public long selectSqlCount(String countSql, Object... params) {
			Query queryCount = this.getEntityManager().createNativeQuery(countSql);
			setParameters(queryCount, params);
			String c = queryCount.getResultList().get(0).toString();
			return Long.parseLong(c);
		}
		/*
		 * (non-Javadoc)
		 * 
		 * @see com.tentcoo.core.dao.BaseDao#batchSave(java.util.List)
		 */

		public void batchSave(List<T> entities) {
			EntityManager em = this.getEntityManager();
			int count = 0;
			for (T entity : entities) {
				em.persist(entity);
				count++;
				if (count % 200 == 0) {
					em.flush();
					em.clear();
				}
			}
			em.flush();
			em.clear();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.tentcoo.core.dao.BaseDao#queryForSingle(java.lang.Class,
		 * java.lang.String, java.lang.Object[])
		 */

		public <E> E queryForSingle(Class<E> resultType, String jpql,
				Object... params) {
			TypedQuery<E> query = this.getQuery(jpql, resultType);
			setParameters(query, params);
			List<E> results = query.getResultList();
			if (null == results || results.isEmpty())
				return null;
			if (this.LOG.isInfoEnabled() && results.size() > 1) {
				this.LOG.info(jpql + ": 有多个结果");
			}
			return results.get(0);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.tentcoo.core.dao.BaseDao#queryForList(java.lang.Class,
		 * java.lang.String, java.lang.Object[])
		 */

		public <E> List<E> queryForList(Class<E> resultType, String jpql,
				Object... params) {
			return this.queryForList(resultType, jpql, -1, -1, params);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.tentcoo.core.dao.BaseDao#queryForList(java.lang.Class,
		 * java.lang.String, int, int, java.lang.Object[])
		 */

		public <E> List<E> queryForList(Class<E> resultType, String jpql,
				int firstResult, int maxResults, Object... params) {
			TypedQuery<E> query = this.getQuery(jpql, resultType);
			setParameters(query, params);
			if (firstResult > -1 && maxResults > -1) {
				query.setFirstResult(firstResult).setMaxResults(maxResults);
			}
			return query.getResultList();
		}

		/**
		 * 将属性连接起来
		 * 
		 * @param properties
		 *            属性数组
		 * @return 如果属性数组为空，或者长度为0，则返回""空字符串，否则返回"o.username=?,o.password=?"
		 */
		protected static String buildProperties(String[] properties) {
			if (null == properties || properties.length == 0)
				return "";
			StringBuilder sb = new StringBuilder();
			for (String property : properties) {
				sb.append("o.").append(property).append("=?,");
			}
			sb.deleteCharAt(sb.length() - 1);
			return sb.toString();
		}

		/**
		 * 拼凑orderBy语句（当order不为null，且包含最少一个元素时才会进行拼凑）
		 * 
		 * @param order
		 *            排序
		 * @param sb
		 *            包含jpql语句的StringBuilder
		 */
		protected static void buildOrderBy(Order order, StringBuilder sb) {
			if (null != order && !order.isEmpty()) {
				sb.append(" order by ");
				for (String key : order.keySet()) {
					sb.append("o.").append(key).append(" ").append(order.get(key))
							.append(",");
				}
				sb.deleteCharAt(sb.length() - 1);
			}
		}

		/**
		 * 拼凑where语句（当whereSql不为空的且不为空字符串的时候，才有进行拼凑）
		 * 
		 * @param whereSql
		 *            where语句
		 * @param sb
		 *            包含jpql语句的StringBuilder
		 */
		protected static void buildWhereSql(String whereSql, StringBuilder sb) {
			if (null != whereSql && !"".equals(whereSql.trim())) {
				sb.append(" where ").append(whereSql.trim()).append(" ");
			}
		}

		/**
		 * 设置参数
		 * 
		 * @param query
		 *            查询query
		 * @param params
		 *            参数数组
		 */
		protected static void setParameters(Query query, Object[] params) {
			if (null != query && null != params && params.length > 0) {
				for (int i = 1; i <= params.length; i++) {
					System.out.println(params.toString());
					query.setParameter(i, params[i - 1]);
				}
			}
		}

		/**
		 * 获得实体ID名称，主键
		 * <p>
		 * 先看看字段有没有注解Id,如果字段上没有注解，则在getter方法上面找.
		 * </p>
		 * 
		 * @return
		 * @throws com.blackants.core.exception.DaoException
		 *             没有对id进行注解时，或者在获取Class描述发生错误时
		 */
		private String getEntityIdName() {
			if (null != this.entityIdName && !"".equals(this.entityIdName))
				return this.entityIdName;
			Field[] fields = this.entityClass.getDeclaredFields();
			Id id = null;
			String entityId = null;
			// 先看看字段有没有注解Id
			for (Field field : fields) {
				id = field.getAnnotation(Id.class);
				if (null != id) {
					entityId = field.getName();
					break;
				}
			}
			// 如果字段上没有注解，则在getter方法上面找.
			if (null == id) {
				try {
					PropertyDescriptor[] propertyDescriptors = Introspector
							.getBeanInfo(this.entityClass).getPropertyDescriptors();
					Method readMethod = null;
					for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
						readMethod = propertyDescriptor.getReadMethod();
						id = readMethod.getAnnotation(Id.class);
						if (null != id) {
							entityId = propertyDescriptor.getName();
							break;
						}
					}
				} catch (IntrospectionException e) {
					throw new DaoException(e);
				}
			}

			if (entityId == null)
				throw new DaoException("主键没有设置");

			return entityId;
		}

		/**
		 * 获得实体的类名
		 * 
		 * @return 如果注解上面没有写name属性，则直接使用类名，否则返回注解上面的name值
		 */
		protected String getEntityName() {
			String entityName = this.entityClass.getSimpleName();
			Entity entity = this.entityClass.getAnnotation(Entity.class);
			String name = null;
			if (null != entity)
				name = entity.name();
			return null == name || "".equals(name.trim()) ? entityName : name
					.trim();
		}

		/**
		 * 获取EntityManager对象
		 * 
		 * @return 返回当前的线程的EntityManager对象
		 */
		protected EntityManager getEntityManager() {
			return this.em;
		}
		/**
		 * 默认是实体作为类别，获取query对象
		 * 
		 * @param jpql
		 *            jpql语句
		 * @return 返回TypedQuery
		 * @see javax.persistence.TypedQuery
		 */
		protected TypedQuery<T> getQueryWithDefaultType(String jpql) {
			return this.getEntityManager().createQuery(jpql, this.entityClass);
		}
		/**
		 * 加悲观锁
		 * 
		 * @param jpql
		 * @return
		 */
		protected TypedQuery<T> getQueryWithDefaultTypeLock(String jpql) {
			return this.getEntityManager().createQuery(jpql, this.entityClass)
					.setLockMode(LockModeType.PESSIMISTIC_WRITE);
		}
		/**
		 * 自动识别类别，获取query对象
		 * 
		 * @param jpql
		 *            jpql语句
		 * @return 返回query
		 * @see javax.persistence.Query
		 */
		protected Query getQuery(String jpql) {
			return this.getEntityManager().createQuery(jpql);
		}

		/**
		 * 通过返回类型获取query对象
		 * 
		 * @param jpql
		 *            jpql语句
		 * @param resultClass
		 *            返回类型
		 * @return 返回TypedQuery
		 * @see javax.persistence.TypedQuery
		 */
		protected <X> TypedQuery<X> getQuery(String jpql, Class<X> resultClass) {
			return this.getEntityManager().createQuery(jpql, resultClass);
		}

		/**
		 * @return the jdbcTemplate
		 */
		protected JdbcTemplate getJdbcTemplate() {
			return this.jdbcTemplate;
		}

		/**
		 * @return the namedParameterJdbcTemplate
		 */
		protected NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
			return this.namedParameterJdbcTemplate;
		}

		/**
		 * @return the redisTemplate
		 */
		// public RedisTemplate<String, String> getRedisTemplate() {
		// return this.redisTemplate;
		// }
}
